using System;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.Configuration;
using System.Collections;
using System.Web.Profile;
using System.Configuration;

using Azke.Core.Domain;
using Azke.Core.Service;
using Azke.Core.Util;

namespace Azke.Core.Security
{
    public class NHMembershipProvider : MembershipProvider 
    {

        #region Private Members

        private LogManager _logger = LogManager.GetLogger();
        private const string _encryptionKey = "AE09F72B007CAAB5";
        private CoreRepository _coreRepository;

        private string _applicationName;
        private bool _enablePasswordReset;
        private bool _enablePasswordRetrieval;
        private int _maxInvalidPasswordAttempts;
        private int _minRequiredNonAlphanumericCharacters;
        private int _minRequiredPasswordLength;
        private int _passwordAttemptWindow;
        private MembershipPasswordFormat _passwordFormat;
        private string _passwordStrengthRegularExpression;
        private bool _requiresQuestionAndAnswer;
        private bool _requiresUniqueEmail;
        

        #endregion

        #region Constructor
        //
        // Summary:
        //     Initializes a new instance of the System.Web.Security.SqlMembershipProvider
        //     class.
        public NHMembershipProvider()
        {
            // NHibernate Session
            //this._coreRepository = (CoreRepository)HttpContext.Current.Items["CoreRepository"];
            
        }

        #endregion

        #region Initializor
        //
        // Summary:
        //     Initializes the NHibernate membership provider with the property values specified
        //     in the ASP.NET application's configuration file. This method is not intended
        //     to be used directly from your code.
        //
        // Parameters:
        //   config:
        //     A System.Collections.Specialized.NameValueCollection that contains the names
        //     and values of configuration options for the membership provider.
        //
        //   name:
        //     The name of the Azke.Core.Security.NHMembershipProvider instance to initialize.
        //
        // Exceptions:
        //   System.Web.HttpException:
        //     The current trust level is less than Low.
        //
        //   System.ArgumentNullException:
        //     config is null.
        //
        //   System.InvalidOperationException:
        //     The provider has already been initialized prior to the current call to the
        //     System.Web.Security.SqlMembershipProvider.Initialize(System.String,System.Collections.Specialized.NameValueCollection)
        //     method.
        //
        //   System.Configuration.Provider.ProviderException:
        //     The enablePasswordRetrieval, enablePasswordReset, requiresQuestionAndAnswer,
        //     or requiresUniqueEmail attribute is set to a value other than a Boolean.-
        //     or -The maxInvalidPasswordAttempts or the passwordAttemptWindow attribute
        //     is set to a value other than a positive integer.- or -The minRequiredPasswordLength
        //     attribute is set to a value other than a positive integer, or the value is
        //     greater than 128.- or -The minRequiredNonalphanumericCharacters attribute
        //     is set to a value other than zero or a positive integer, or the value is
        //     greater than 128.- or -The value for the passwordStrengthRegularExpression
        //     attribute is not a valid regular expression.- or -The applicationName attribute
        //     is set to a value that is greater than 256 characters.- or -The passwordFormat
        //     attribute specified in the application configuration file is an invalid System.Web.Security.MembershipPasswordFormat
        //     enumeration.- or -The passwordFormat attribute is set to System.Web.Security.MembershipPasswordFormat.Hashed
        //     and the enablePasswordRetrieval attribute is set to true in the application
        //     configuration.- or -The passwordFormat attribute is set to Encrypted and
        //     the machineKey configuration element specifies AutoGenerate for the decryptionKey
        //     attribute.- or -The connectionStringName attribute is empty or does not exist
        //     in the application configuration.- or - The value of the connection string
        //     for the connectionStringName attribute value is empty, or the specified connectionStringName
        //     does not exist in the application configuration file.- or - The value for
        //     the commandTimeout attribute is set to a value other than zero or a positive
        //     integer.- or -The application configuration file for this Azke.Core.Security.NHMembershipProvider
        //     instance contains an unrecognized attribute.
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {         
            if (config == null)
                throw new ArgumentNullException("config");

            if (name == null || name.Length == 0)
                name = "NHMembershipProvider";

            if (String.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "NHibernate Membership provider");
            }

            // Initialize the abstract base class.
            base.Initialize(name, config);

            _applicationName = GetConfigValue(config["applicationName"],
                                             "/"); 
            _enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
            _enablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "false"));
            _maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
            _minRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
            _minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
            _passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
            _passwordStrengthRegularExpression= Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
            _requiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "true"));
            _requiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "false"));
        
            string temp_format = config["passwordFormat"];
            if (temp_format == null)
            {
                temp_format = "Hashed";
            }

            switch (temp_format)
            {
                case "Hashed":
                    _passwordFormat = MembershipPasswordFormat.Hashed;
                    break;
                case "Encrypted":
                    _passwordFormat = MembershipPasswordFormat.Encrypted;
                    break;
                case "Clear":
                    _passwordFormat = MembershipPasswordFormat.Clear;
                    break;
                default:
                    throw new System.Configuration.Provider.ProviderException("Password format not supported.");
            }

            // NHibernate Session
            try
            {
                this._coreRepository = (CoreRepository)HttpContext.Current.Items["CoreRepository"];
                this._logger.Write(LogLevel.DEBUG, this.ToString(), "CoreRepository from HttpContext used.");
            }
            catch
            {
                this._coreRepository = new CoreRepository(true);
                this._logger.Write(LogLevel.WARN, this.ToString(), "No CoreRepository in HttpContext found, creating new CoreRepository.");
            }
           
        }
        #endregion

        #region Helper functions
        //
        // A helper function to retrieve config values from the configuration file.
        //
        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (String.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }
        //
        // A helper function to validate passwords.
        //
        /*public void OnValidatingPassword(object sender,ValidatePasswordEventArgs args)
        {
            System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"(?=.{" + _minRequiredPasswordLength + @",})(?=(.*\W){" + __minRequiredNonAlphanumericCharacters + @"1,})");
            if (!r.IsMatch(args.Password))
            {
                args.FailureInformation = new HttpException(String.Format("Password must be at least {0} characters long and " +
                        "contain at least {1} non-alphanumeric character.", _minRequiredPasswordLength, _minRequiredNonAlphanumericCharacters);
                args.Cancel = true;
            }
        }*/

        


        

        

 

        /*/// <summary>
        /// Create a MD5 hash of the password.
        /// </summary>
        /// <param name="password">The password in clear text</param>
        /// <returns>The MD5 hash of the password</returns>
        private string HashPassword(string password)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider md5 = 
                new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] encryptedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(password));
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < encryptedBytes.Length; i++)
            {
                sb.AppendFormat("{0:x2}", encryptedBytes[i]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// Generates a new password and returns a hashed password.
        /// </summary>
        /// <returns>The newly created password.</returns>
        private string GeneratePassword()
        {
            int length = 8;
            string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            string pwd = String.Empty;
            Random rnd = new Random();
            for (int i = 0; i < length; i++)
            {
                pwd += chars[rnd.Next(chars.Length)];
            }
            this._generatedPassword = pwd;
            return HashPassword(pwd);
        }*/

        //
        // Check username for commas and length
        //
        private bool ValidateUserName(string username)
        {
            if (username.Contains(",") || username.Length > 50)
                return false;
            else
                return true;
        }

        #endregion

        #region Properties
        //
        // Summary:
        //     Gets or sets the name of the application to store and retrieve membership
        //     information for.
        //
        // Returns:
        //     The name of the application to store and retrieve membership information
        //     for. The default is the System.Web.HttpRequest.ApplicationPath property value
        //     for the current System.Web.HttpContext.Request.
        public override string ApplicationName 
        {
            get { return _applicationName; }
            set { _applicationName = value; }
        }
        //
        // Summary:
        //     Gets a value indicating whether the Nhibernate membership provider is configured
        //     to allow users to reset their passwords.
        //
        // Returns:
        //     true if the membership provider supports password reset; otherwise, false.
        //     The default is true.
        public override bool EnablePasswordReset 
        {
            get { return _enablePasswordReset; } 
        }
        //
        // Summary:
        //     Gets a value indicating whether the NHibernate membership provider is configured
        //     to allow users to retrieve their passwords.
        //
        // Returns:
        //     true if the membership provider supports password retrieval; otherwise, false.
        //     The default is false.
        public override bool EnablePasswordRetrieval
        {
            get { return _enablePasswordRetrieval; }
        }
        //
        // Summary:
        //     Gets the number of invalid password or password-answer attempts allowed before
        //     the membership user is locked out.
        //
        // Returns:
        //     The number of invalid password or password-answer attempts allowed before
        //     the membership user is locked out.
        public override int MaxInvalidPasswordAttempts
        { 
            get { return _maxInvalidPasswordAttempts; } 
        }
        //
        // Summary:
        //     Gets the minimum number of special characters that must be present in a valid
        //     password.
        //
        // Returns:
        //     The minimum number of special characters that must be present in a valid
        //     password.
        public override int MinRequiredNonAlphanumericCharacters 
        {
            get { return _minRequiredNonAlphanumericCharacters; }
        }
        //
        // Summary:
        //     Gets the minimum length required for a password.
        //
        // Returns:
        //     The minimum length required for a password.
        public override int MinRequiredPasswordLength
        { 
            get { return _minRequiredPasswordLength; }
        }
        //
        // Summary:
        //     Gets the number of minutes in which a maximum number of invalid password
        //     or password-answer attempts are allowed before the membership user is locked
        //     out.
        //
        // Returns:
        //     The number of minutes in which a maximum number of invalid password or password-answer
        //     attempts are allowed before the membership user is locked out.
        public override int PasswordAttemptWindow 
        {
            get { return _passwordAttemptWindow; }
        }
        //
        // Summary:
        //     Gets a value indicating the format for storing passwords in the NHibernate
        //     membership database.
        //
        // Returns:
        //     One of the System.Web.Security.MembershipPasswordFormat values, indicating
        //     the format for storing passwords in the NHibernate controlled database.
        public override MembershipPasswordFormat PasswordFormat 
        {
            get { return _passwordFormat; }
        }
        //
        // Summary:
        //     Gets the regular expression used to evaluate a password.
        //
        // Returns:
        //     A regular expression used to evaluate a password.
        public override string PasswordStrengthRegularExpression 
        {
            get { return _passwordStrengthRegularExpression; }
        }
        //
        // Summary:
        //     Gets a value indicating whether the NHibernate membership provider is configured
        //     to require the user to answer a password question for password reset and
        //     retrieval.
        //
        // Returns:
        //     true if a password answer is required for password reset and retrieval; otherwise,
        //     false. The default is true.
        public override bool RequiresQuestionAndAnswer 
        {
            get { return _requiresQuestionAndAnswer; }
        }
        //
        // Summary:
        //     Gets a value indicating whether the NHibernate membership provider is configured
        //     to require a unique e-mail address for each user name.
        //
        // Returns:
        //     true if the membership provider requires a unique e-mail address; otherwise,
        //     false. The default is false.
        public override bool RequiresUniqueEmail 
        {
            get { return _requiresUniqueEmail; }
        }
        #endregion

        #region Methods
        //
        // Summary:
        //     Returns a collection of membership users for which the e-mail address field
        //     contains the specified e-mail address.
        //
        // Parameters:
        //   totalRecords:
        //     The total number of matched users.
        //
        //   pageIndex:
        //     The index of the page of results to return. pageIndex is zero-based.
        //
        //   emailToMatch:
        //     The e-mail address to search for.
        //
        //   pageSize:
        //     The size of the page of results to return.
        //
        // Returns:
        //     A System.Web.Security.MembershipUserCollection that contains a page of pageSizeSystem.Web.Security.MembershipUser
        //     objects beginning at the page specified by pageIndex.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     emailToMatch is longer than 256 characters.- or -pageIndex is less than zero.-
        //     or -pageSize is less than one.- or -pageIndex multiplied by pageSize plus
        //     pageSize minus one exceeds System.Int32.MaxValue.
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            if (pageIndex < 0 || pageSize < 1 || ((pageIndex * pageSize - 1) > System.Int32.MaxValue))
                throw new System.ArgumentException("Supplied values are not valid");

            if (emailToMatch.Length > 256)
                throw new System.ArgumentException("Provided email address exceeds maximum length.");

            MembershipUserCollection pagedUsers = new MembershipUserCollection();
            totalRecords = 0;

            try
            {
                IList users = this._coreRepository.FindUsersByEmail(emailToMatch);
                totalRecords = users.Count;

                if (totalRecords <= 0)
                {
                    return pagedUsers;
                }
                else
                {
                    int startIndex = pageSize * pageIndex;
                    int endIndex = startIndex + pageSize - 1;
                    int counter = 0;

                    foreach (User user in users)
                    {
                        if (counter >= startIndex)
                        {
                            MembershipUser membershipUser =
                                new MembershipUser(this.Name,
                                                    user.UserName,
                                                    user.ProviderUserKey,
                                                    user.Email,
                                                    user.PasswordQuestion,
                                                    user.Comment,
                                                    user.IsApproved,
                                                    user.IsLockedOut,
                                                    user.CreationDate,
                                                    user.LastLoginDate,
                                                    user.LastActivityDate,
                                                    user.LastPasswordChangedDate,
                                                    user.LastLockedOutDate);
                            pagedUsers.Add(membershipUser);
                            counter++;
                        }

                        if (counter >= endIndex)
                        {
                            return pagedUsers;
                        }
                    }
                    return pagedUsers;
                }             
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while searching for user with matching email {0}.", emailToMatch), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while searching for user with matching email '{0}'", emailToMatch));
            }
        }

        //
        // Summary:
        //     Returns the password for the specified user name from the NHibernate membership
        //     database.
        //
        // Parameters:
        //   passwordAnswer:
        //     The password answer for the user.
        //
        //   username:
        //     The user to retrieve the password for.
        //
        // Returns:
        //     The password for the specified user name.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     One of the parameter values exceeds the maximum allowed length.- or -username
        //     is an empty string (""), contains a comma, or is longer than 256 characters.-
        //     or -passwordAnswer is an empty string and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer
        //     is true.- or -passwordAnswer is greater than 128 characters.- or -The encoded
        //     version of passwordAnswer is greater than 128 characters.
        //
        //   System.NotSupportedException:
        //     System.Web.Security.SqlMembershipProvider.EnablePasswordRetrieval is set
        //     to false.
        //
        //   System.ArgumentNullException:
        //     username is null.- or -passwordAnswer is null and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer
        //     is true.
        //
        //   System.Configuration.Provider.ProviderException:
        //     username is not found in the membership database.- or -An error occurred
        //     while retrieving the password from the database.
        //
        //   System.Web.Security.MembershipPasswordException:
        //     passwordAnswer is invalid. - or -The membership user identified by username
        //     is locked out.
        public override string GetPassword(string username, string passwordAnswer)
        {
            if (!this._enablePasswordRetrieval)
            {
                throw new System.NotSupportedException("Password Retrieval Not Enabled.");
            }

            if (this._passwordFormat == MembershipPasswordFormat.Hashed)
            {
                throw new System.Configuration.Provider.ProviderException("Cannot retrieve Hashed passwords.");
            }

            // Check for null or empty
            if (string.IsNullOrEmpty(username))
                throw new System.ArgumentNullException("username");
            else if (string.IsNullOrEmpty(passwordAnswer) && this._requiresQuestionAndAnswer)
                throw new System.ArgumentNullException("passwordAnswer");
            else if (!ValidateUserName(username))
                throw new System.ArgumentException("The username is not valid.");

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (user.IsLockedOut)
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Locked out user {0} tried to retrieve password.", username));
                        throw new System.Configuration.Provider.ProviderException("The account is disabled.");
                    }
                    else
                    {
                        string password;
                        if (this._requiresQuestionAndAnswer)
                            password = user.GetPassword(passwordAnswer);
                        else
                            password = user.GetPassword();

                        if (this._requiresQuestionAndAnswer && String.IsNullOrEmpty(password))
                        {
                            throw new MembershipPasswordException("Incorrect password answer.");
                        }

                        return password;
                    }
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    throw new System.Configuration.Provider.ProviderException("The username was not found.");
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to retrieve password, username: {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to retrieve password."));
            }
        }
 
        //
        // Summary:
        //     Gets the information from the data source for the membership user associated
        //     with the specified unique identifier and updates the last activity date/time
        //     stamp for the user, if specified.
        //
        // Parameters:
        //   providerUserKey:
        //     The unique identifier for the user.
        //
        //   userIsOnline:
        //     true to update the last-activity date/time stamp for the specified user;
        //     otherwise, false.
        //
        // Returns:
        //     A System.Web.Security.MembershipUser object representing the user associated
        //     with the specified unique identifier. If no user is found in the database
        //     for the specified providerUserKey value, null is returned.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     providerUserKey is null.
        //
        //   System.ArgumentException:
        //     providerUserKey is not of type System.Guid.
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            // Check for null or empty
            if (providerUserKey == null)
                throw new System.ArgumentNullException("providerUserKey");

            if (!(providerUserKey is Guid))
                throw new System.ArgumentException("The providerUserKey are not valid.");

            try
            {
                User user = this._coreRepository.GetUserByUserKey(providerUserKey);
                if (user != null)
                {
                    if (userIsOnline)
                    {
                        user.LastActivityDate = DateTime.Now;
                        this._coreRepository.UpdateObject(user);
                    }
                    MembershipUser membershipUser =
                            new MembershipUser(this.Name,
                                                user.UserName,
                                                user.ProviderUserKey,
                                                user.Email,
                                                user.PasswordQuestion,
                                                user.Comment,
                                                user.IsApproved,
                                                user.IsLockedOut,
                                                user.CreationDate,
                                                user.LastLoginDate,
                                                user.LastActivityDate,
                                                user.LastPasswordChangedDate,
                                                user.LastLockedOutDate);
                    return membershipUser;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid user key, not found: {0}.", providerUserKey));
                    throw new System.Configuration.Provider.ProviderException("The user key was not found."); ;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to get user, username: {0}.", providerUserKey), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to get user."));
            }
        }
        //
        // Summary:
        //     Modifies a user's password.
        //
        // Parameters:
        //   newPassword:
        //     The new password for the specified user.
        //
        //   oldPassword:
        //     The current password for the specified user.
        //
        //   username:
        //     The user to update the password for.
        //
        // Returns:
        //     true if the password was updated successfully. false if the supplied old
        //     password is invalid, the user is locked out, or the user does not exist in
        //     the database.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     username is null.- or -oldPassword is null.- or -newPassword is null.
        //
        //   System.ArgumentException:
        //     username is an empty string (""), contains a comma, or is longer than 256
        //     characters.- or -oldPassword is an empty string or longer than 128 characters.-
        //     or -newPassword is an empty string or longer than 128 characters.- or -The
        //     encoded version of newPassword is greater than 128 characters.- or -The change-password
        //     action was canceled by a subscriber to the System.Web.Security.Membership.ValidatingPassword
        //     event, and the System.Web.Security.ValidatePasswordEventArgs.FailureInformation
        //     property was null.- or -The length of newPassword is less than the minimum
        //     length specified in the System.Web.Security.SqlMembershipProvider.MinRequiredPasswordLength
        //     property.- or -The number of non-alphabetic characters in newPassword is
        //     less than the required number of non-alphabetic characters specified in the
        //     System.Web.Security.SqlMembershipProvider.MinRequiredNonAlphanumericCharacters
        //     property.- or -newPassword does not pass the regular expression defined in
        //     the System.Web.Security.SqlMembershipProvider.PasswordStrengthRegularExpression
        //     property.
        //
        //   System.Configuration.Provider.ProviderException:
        //     An error occurred while setting the new password value at the database. 
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            // Check for null or empty
            if (string.IsNullOrEmpty(username))
                throw new System.ArgumentNullException("username");
            else if (string.IsNullOrEmpty(oldPassword))
                throw new System.ArgumentNullException("oldPassword");
            else if (string.IsNullOrEmpty(newPassword))
                throw new System.ArgumentNullException("newPassword");

            // Validate user
            if (!ValidateUser(username, oldPassword))
                return false;

            // Validate new password
            ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, false);
            OnValidatingPassword(args);

            if (args.Cancel)
                if (args.FailureInformation != null)
                    throw args.FailureInformation;
                else
                    throw new MembershipPasswordException("Change password canceled due to new password validation failure.");

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (user.ChangePassword(oldPassword, newPassword))
                    {
                        this._coreRepository.UpdateObject(user);
                        // Remove old user from the cache
                        // HttpContext.Current.Cache.Remove(USER_CACHE_PREFIX + currentUser.Id.ToString());
                        return true;
                    }
                    else
                        return false;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    return false;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to change password, username: {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to change password, username: '{0}':", username));
            }
        }

        //
        // Summary:
        //     Updates the password question and answer for a user in the NHibernate membership
        //     database.
        //
        // Parameters:
        //   newPasswordQuestion:
        //     The new password question for the specified user.
        //
        //   newPasswordAnswer:
        //     The new password answer for the specified user.
        //
        //   username:
        //     The user to change the password question and answer for.
        //
        //   password:
        //     The password for the specified user.
        //
        // Returns:
        //     true if the update was successful; otherwise, false. A value of false is
        //     also returned if the password is incorrect, the user is locked out, or the
        //     user does not exist in the database.
        //
        // Exceptions:
        //   System.Configuration.Provider.ProviderException:
        //     An error occurred changing the password question and answer in the database.
        //
        //   System.ArgumentNullException:
        //     username is null.- or -password is null.- or -newPasswordQuestion is null
        //     and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer is
        //     true.- or -newPasswordAnswer is null and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer
        //     is true.
        //
        //   System.ArgumentException:
        //     username is an empty string (""), contains a comma, or is longer than 256
        //     characters.- or -password is an empty string or is longer than 128 characters.-
        //     or -newPasswordQuestion is an empty string or is longer than 256 characters.-
        //     or -newPasswordAnswer is an empty string or is longer than 128 characters.-
        //     or -The encoded version of newPasswordAnswer is longer than 128 characters.
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            // Check for null or empty
            if (string.IsNullOrEmpty(username))
                throw new System.ArgumentNullException("username");
            else if (string.IsNullOrEmpty(password))
                throw new System.ArgumentNullException("password");
            else if (string.IsNullOrEmpty(newPasswordQuestion) && _requiresQuestionAndAnswer)
                throw new System.ArgumentNullException("newPasswordQuestion");
            else if (string.IsNullOrEmpty(newPasswordAnswer) && _requiresQuestionAndAnswer)
                throw new System.ArgumentNullException("newPasswordAnswer");

            // Validate user
            if (!ValidateUser(username, password))
                return false;

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (user.ChangePasswordQuestionAndAnswer(password, newPasswordQuestion, newPasswordAnswer))
                    {
                        // Save changes
                        this._coreRepository.UpdateObject(user);
                        // Remove old user from the cache
                        // HttpContext.Current.Cache.Remove(USER_CACHE_PREFIX + currentUser.Id.ToString());
                        return true;
                    }
                    else
                        return false;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    return false;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to change password question and answer, username: {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to change password question and answer, username: '{0}'", username), ex);
            }
        }

        //
        // Summary:
        //     Adds a new user to the NHibernate membership database.
        //
        // Parameters:
        //   isApproved:
        //     Whether or not the new user is approved to be validated.
        //
        //   passwordAnswer:
        //     The password answer for the new user.
        //
        //   username:
        //     The user name for the new user.
        //
        //   providerUserKey:
        //     A System.Guid that uniquely identifies the membership user in the NHibernate
        //     database.
        //
        //   password:
        //     The password for the new user.
        //
        //   passwordQuestion:
        //     The password question for the new user.
        //
        //   email:
        //     The e-mail address for the new user.
        //
        //   status:
        //     One of the System.Web.Security.MembershipCreateStatus values, indicating
        //     whether the user was created successfully.
        //
        // Returns:
        //     A System.Web.Security.MembershipUser object for the newly created user. If
        //     no user was created, this method returns null.
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            status = MembershipCreateStatus.UserRejected;
            
            // Validate Password
            ValidatePasswordEventArgs args =
              new ValidatePasswordEventArgs(username, password, true);
            OnValidatingPassword(args);
            if (args.Cancel)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }
            // Validate email
            if (this._requiresUniqueEmail && !String.IsNullOrEmpty(GetUserNameByEmail(email)))
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return null;
            }
            // Validate username
            if (!ValidateUserName(username))
            {
                status = MembershipCreateStatus.InvalidUserName;
                return null;
            }
            // Check if username exists
            User usr = this._coreRepository.GetUserByUsername(username);

            if (usr != null)
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return null;
            }
            else
            {
                DateTime createDate = DateTime.Now;
                if (providerUserKey == null)
                {
                    providerUserKey = Guid.NewGuid();
                }
                else
                {
                    if (!(providerUserKey is Guid))
                    {
                        status = MembershipCreateStatus.InvalidProviderUserKey;
                        return null;
                    }
                }
                
                try
                {
                    if (String.IsNullOrEmpty(passwordAnswer) && this._requiresQuestionAndAnswer)
                        throw new ArgumentException("Password answer must be specified");

                    if (String.IsNullOrEmpty(passwordQuestion) && this._requiresQuestionAndAnswer)
                        throw new ArgumentException("Password question must be specified");

                    // Finally create the new user
                    User newUser = 
                           new User(this.Name, 
                                    username,
                                    (Guid)providerUserKey,
                                    email,
                                    password,
                                    passwordQuestion,
                                    passwordAnswer,
                                    "",
                                    isApproved,
                                    false);

                    // Save the new user
                    this._coreRepository.SaveObject(newUser);
                    status = MembershipCreateStatus.Success;
                    
                    // The new user must be added to the default Autenticated role
                    string authRole = ConfigurationManager.AppSettings["AuthenticatedRole"];
                    if (!String.IsNullOrEmpty(authRole))
                        Roles.AddUserToRole(username, authRole);
                    
                    MembershipUser newSavedUser = GetUser(username, false);
                    return newSavedUser;
                }
                catch (Exception ex)
                {
                    this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to create new user {0}.", username), ex);
                    status = MembershipCreateStatus.ProviderError;
                }
            }
            status = MembershipCreateStatus.ProviderError;
            return null;
        }

        //
        // Summary:
        //     Removes a user's membership information from the NHibernate membership database.
        //
        // Parameters:
        //   username:
        //     The name of the user to delete.
        //
        //   deleteAllRelatedData:
        //     true to delete data related to the user from the database; false to leave
        //     data related to the user in the database.
        //
        // Returns:
        //     true if the user was deleted; otherwise, false. A value of false is also
        //     returned if the user does not exist in the database.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     username is an empty string (""), contains a comma, or is longer than 50
        //     characters.
        //
        //   System.ArgumentNullException:
        //     username is null.
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            // Check for null, empty, comma and length
            if (string.IsNullOrEmpty(username) || !ValidateUserName(username))
                throw new System.ArgumentException(String.Format("Not a valid username: {0}.", username));

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    // Delete all roles, profile, ...
                    if (deleteAllRelatedData)
                    {
                        // Profilesettings, Consider throw here if false? 
                        // ...or a new user with same UserName will "inherit" Profile Settings...
                        if (!ProfileManager.DeleteProfile(username))
                            this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Could not delete user '{0}' profile data.", username));
                    }
                    // Finally, delete user
                    this._coreRepository.DeleteObject(user);
                    // Remove old user from the cache (not implemented)
                    // HttpContext.Current.Cache.Remove(USER_CACHE_PREFIX + currentUser.Id.ToString());
                    return true;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    return false;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to delete user {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to delete user."));
            }

        }

        //
        // Summary:
        //     Gets a collection of membership users where the user name contains the specified
        //     user name to match.
        //
        // Parameters:
        //   totalRecords:
        //     When this method returns, contains the total number of matched users.
        //
        //   pageIndex:
        //     The index of the page of results to return. pageIndex is zero-based.
        //
        //   usernameToMatch:
        //     The user name to search for.
        //
        //   pageSize:
        //     The size of the page of results to return.
        //
        // Returns:
        //     A System.Web.Security.MembershipUserCollection that contains a page of pageSizeSystem.Web.Security.MembershipUser
        //     objects beginning at the page specified by pageIndex.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     usernameToMatch is an empty string ("") or is longer than 256 characters.-
        //     or -pageIndex is less than zero.- or -pageSize is less than 1.- or -pageIndex
        //     multiplied by pageSize plus pageSize minus one exceeds System.Int32.MaxValue.
        //
        //   System.ArgumentNullException:
        //     usernameToMatch is null.
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            if (pageIndex < 0 || pageSize < 1 || ((pageIndex * pageSize - 1) > System.Int32.MaxValue))
                throw new System.ArgumentException("Supplied values are not valid");

            if (!ValidateUserName(usernameToMatch))
                throw new System.ArgumentException("Provided username not valid.");

            MembershipUserCollection pagedUsers = new MembershipUserCollection();
            totalRecords = 0;

            try
            {
                IList users = this._coreRepository.FindUsersByUsername(usernameToMatch);
                totalRecords = users.Count;

                if (totalRecords <= 0)
                {
                    return pagedUsers;
                }
                else
                {
                    int startIndex = pageSize * pageIndex;
                    int endIndex = startIndex + pageSize - 1;
                    int counter = 0;

                    foreach (User user in users)
                    {
                        if (counter >= startIndex)
                        {
                            MembershipUser membershipUser =
                                new MembershipUser(this.Name,
                                                    user.UserName,
                                                    user.ProviderUserKey,
                                                    user.Email,
                                                    user.PasswordQuestion,
                                                    user.Comment,
                                                    user.IsApproved,
                                                    user.IsLockedOut,
                                                    user.CreationDate,
                                                    user.LastLoginDate,
                                                    user.LastActivityDate,
                                                    user.LastPasswordChangedDate,
                                                    user.LastLockedOutDate);
                            pagedUsers.Add(membershipUser);
                            counter++;
                        }

                        if (counter >= endIndex)
                        {
                            return pagedUsers;
                        }
                    }
                    return pagedUsers;
                } 
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while searching for user with matching username {0}.", usernameToMatch), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while searching for user with matching username '{0}'", usernameToMatch));
            }
        }

        //
        // Summary:
        //     Gets a collection of all the users in the NHibernate membership database.
        //
        // Parameters:
        //   totalRecords:
        //     The total number of users.
        //
        //   pageIndex:
        //     The index of the page of results to return. pageIndex is zero-based.
        //
        //   pageSize:
        //     The size of the page of results to return.
        //
        // Returns:
        //     A System.Web.Security.MembershipUserCollection of System.Web.Security.MembershipUser
        //     objects representing all the users in the database for the configured Azke.Core.Security.NHMembershipProvider.ApplicationName.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     pageIndex is less than zero.- or -pageSize is less than one.- or -pageIndex
        //     multiplied by pageSize plus pageSize minus one exceeds System.Int32.MaxValue.
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            if (pageIndex < 0 || pageSize < 1 || ((pageIndex * pageSize - 1) > System.Int32.MaxValue))
                throw new System.ArgumentException("Supplied values are not valid");

            MembershipUserCollection pagedUsers = new MembershipUserCollection();
            totalRecords = 0;

            try
            {
                IList users = this._coreRepository.GetAll(typeof(User), "UserName");
                totalRecords = users.Count;

                if (totalRecords <= 0)
                {
                    return pagedUsers;
                }
                else
                {
                    int startIndex = pageSize * pageIndex;
                    int endIndex = startIndex + pageSize - 1;
                    int counter = 0;

                    foreach (User user in users)
                    {
                        if (counter >= startIndex)
                        {
                            MembershipUser membershipUser =
                                new MembershipUser(this.Name,
                                                    user.UserName,
                                                    user.ProviderUserKey,
                                                    user.Email,
                                                    user.PasswordQuestion,
                                                    user.Comment,
                                                    user.IsApproved,
                                                    user.IsLockedOut,
                                                    user.CreationDate,
                                                    user.LastLoginDate,
                                                    user.LastActivityDate,
                                                    user.LastPasswordChangedDate,
                                                    user.LastLockedOutDate);
                            pagedUsers.Add(membershipUser);
                            counter++;
                        }

                        if (counter >= endIndex)
                        {
                            return pagedUsers;
                        }
                    }
                    return pagedUsers;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), "An error occured while collecting all users from database.", ex);
                throw new System.Configuration.Provider.ProviderException("An error occured while collecting all users from database. " + ex.Message);
            }
        }
        //
        // Summary:
        //     Returns the number of users currently accessing the application.
        //
        // Returns:
        //     The number of users currently accessing the application.
        public override int GetNumberOfUsersOnline()
        {
            TimeSpan onlineSpan = new TimeSpan(0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0);
            DateTime compareTime = DateTime.Now.Subtract(onlineSpan);

            try
            {
                int numberOfUsers = this._coreRepository.GetNumberOfUsersOnline(compareTime);
                return numberOfUsers;
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), "An error occured while counting users online.", ex);
                throw new System.Configuration.Provider.ProviderException("An error occured while counting users online.");
            }
        }
        
        //
        // Summary:
        //     Returns information from the NHibernate membership database for a user and
        //     provides an option to update the last activity date/time stamp for the user.
        //
        // Parameters:
        //   username:
        //     The name of the user to get information for.
        //
        //   userIsOnline:
        //     true to update the last activity date/time stamp for the user; false to return
        //     user information without updating the last activity date/time stamp for the
        //     user.
        //
        // Returns:
        //     A System.Web.Security.MembershipUser object representing the specified user.
        //     If no user is found in the database for the specified username value, null
        //     is returned.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     username exceeds 256 characters.- or -username contains a comma.
        //
        //   System.ArgumentNullException:
        //     username is null.
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            // Check for null or empty
            if (string.IsNullOrEmpty(username))
                throw new System.ArgumentNullException("username");

            if (!ValidateUserName(username))
                throw new System.ArgumentException("The username is not valid.");

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (userIsOnline)
                    {
                        user.LastActivityDate = DateTime.Now;
                        this._coreRepository.UpdateObject(user);
                    }
                    MembershipUser membershipUser =
                            new MembershipUser(this.Name,
                                                user.UserName,
                                                user.ProviderUserKey,
                                                user.Email,
                                                user.PasswordQuestion,
                                                user.Comment,
                                                user.IsApproved,
                                                user.IsLockedOut,
                                                user.CreationDate,
                                                user.LastLoginDate,
                                                user.LastActivityDate,
                                                user.LastPasswordChangedDate,
                                                user.LastLockedOutDate);
                    return membershipUser;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    throw new System.Configuration.Provider.ProviderException("The username was not found.");
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to get user '{0}'.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to get user."));
            }
        }
        //
        // Summary:
        //     Gets the user name associated with the specified e-mail address.
        //
        // Parameters:
        //   email:
        //     The e-mail address to search for.
        //
        // Returns:
        //     The user name associated with the specified e-mail address. If no match is
        //     found, this method returns null.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     email exceeds 256 characters.
        //
        //   System.Configuration.Provider.ProviderException:
        //     More than one user with the same e-mail address exists in the database and
        //     System.Web.Security.SqlMembershipProvider.RequiresUniqueEmail is true.
        public override string GetUserNameByEmail(string email)
        {
            if (email.Length > 256)
                throw new System.ArgumentException("Provided email address exceeds maximum length.");

            try
            {
                IList users = this._coreRepository.FindUsersByEmail(email);
                if (users.Count > 1)
                {
                    if (_requiresUniqueEmail)
                    {
                        this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("Application requires unique email but still we have several matches for '{0}'.", email));
                        throw new System.Configuration.Provider.ProviderException(String.Format("Error, several users with same email address '{0}'.", email));
                    }
                    else
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Unable to get username, several matches for email '{0}'.", email));
                        return null;
                    }
                }
                else if (users.Count == 1)
                {
                    User user = (User)users[0];
                    return user.UserName;
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("User with email address '{0}' not found.", email));
                    return null;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while searching for user with email {0}.", email), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while searching for user with email."));
            }
        }

        //
        // Summary:
        //     Resets a user's password to a new, automatically generated password.
        //
        // Parameters:
        //   passwordAnswer:
        //     The password answer for the specified user.
        //
        //   username:
        //     The user to reset the password for.
        //
        // Returns:
        //     The new password for the specified user.
        //
        // Exceptions:
        //   System.Configuration.Provider.ProviderException:
        //     username is not found in the membership database.- or -The change password
        //     action was canceled by a subscriber to the System.Web.Security.Membership.ValidatePassword
        //     event and the System.Web.Security.ValidatePasswordEventArgs.FailureInformation
        //     property was null.- or -An error occurred while retrieving the password from
        //     the database.
        //
        //   System.NotSupportedException:
        //     System.Web.Security.SqlMembershipProvider.EnablePasswordReset is set to false.
        //
        //   System.ArgumentException:
        //     username is an empty string (""), contains a comma, or is longer than 256
        //     characters.- or -passwordAnswer is an empty string or is longer than 128
        //     characters and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer
        //     is true.- or -passwordAnswer is longer than 128 characters after encoding.
        //
        //   System.ArgumentNullException:
        //     username is null.- or -passwordAnswer is null and System.Web.Security.SqlMembershipProvider.RequiresQuestionAndAnswer
        //     is true.
        //
        //   System.Web.Security.MembershipPasswordException:
        //     passwordAnswer is invalid. - or -The user account is currently locked out.
        public override string ResetPassword(string username, string passwordAnswer)
        {
            if (!this._enablePasswordReset)
            {
                throw new NotSupportedException("Password reset is not enabled.");
            }

            if (String.IsNullOrEmpty(passwordAnswer) && this._requiresQuestionAndAnswer)
            {
                throw new ArgumentException("Password answer required for password reset.");
            }

            // Check for null or empty
            if (string.IsNullOrEmpty(username) || !ValidateUserName(username))
                throw new System.ArgumentException("username");

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (user.IsLockedOut)
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Locked out user {0}, tried to reset password.", username));
                        throw new System.Web.Security.MembershipPasswordException("The account is disabled.");
                    }
                    else
                    {
                        string newPassword;
                        if (this._requiresQuestionAndAnswer)
                            newPassword = user.ResetPassword(passwordAnswer);
                        else
                            newPassword = user.ResetPassword();

                        if (this._requiresQuestionAndAnswer && String.IsNullOrEmpty(newPassword))
                        {
                            throw new MembershipPasswordException("Incorrect password answer.");
                        }
                        else
                        {
                            this._coreRepository.UpdateObject(user);
                            return newPassword;
                        }
                    }
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username, not found: {0}.", username));
                    throw new System.Configuration.Provider.ProviderException("The username was not found."); ;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to reset password, username: {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to reset password."));
            }
        }
        //
        // Summary:
        //     Clears the user's locked-out status so that the membership user can be validated.
        //
        // Parameters:
        //   username:
        //     The name of the membership user to clear the locked-out status for.
        //
        // Returns:
        //     true if the membership user was successfully unlocked; otherwise, false.
        //     A value of false is also returned if the user does not exist in the database.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     username is an empty string, is longer than 256 characters, or contains a
        //     comma.
        //
        //   System.ArgumentNullException:
        //     username is null.
        public override bool UnlockUser(string username)
        {
            if (String.IsNullOrEmpty(username))
                throw new System.ArgumentNullException("username");
            else if (!ValidateUserName(username))
                throw new System.ArgumentException(String.Format("Invalid username '{0}'.", username)); 

            try
            {
                User user = this._coreRepository.GetUserByUsername(username);
                if (user != null)
                {
                    if (user.IsLockedOut)
                    {
                        if (user.UnlockUser())
                        {
                            this._coreRepository.UpdateObject(user);
                            return true;
                        }

                        return false;
                    }
                    else
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Trying to unlock a user '{0}' which is not locked.", username));
                        throw new System.Configuration.Provider.ProviderException("The account you are trying to enable are not disabled.");
                    }
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Unlocking invalid username, not found: {0}.", username));
                    return false;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to unlock user {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to unlock user {0}.", username), ex);
            }
        }
        //
        // Summary:
        //     Updates information about a user in the NHibernate membership database.
        //
        // Parameters:
        //   user:
        //     A System.Web.Security.MembershipUser object that represents the user to update
        //     and the updated information for the user.
        //
        // Exceptions:
        //   System.ArgumentException:
        //     The System.Web.Security.MembershipUser.UserName property of user is an empty
        //     string (""), contains a comma, or is longer than 256 characters.- or -The
        //     System.Web.Security.MembershipUser.Email property of user is longer than
        //     256 characters.- or -The System.Web.Security.MembershipUser.Email property
        //     of user is an empty string and System.Web.Security.SqlMembershipProvider.RequiresUniqueEmail
        //     is set to true.
        //
        //   System.Configuration.Provider.ProviderException:
        //     The System.Web.Security.MembershipUser.UserName property of user was not
        //     found in the database.- or -The System.Web.Security.MembershipUser.Email
        //     property of user was equal to an existing e-mail address in the database
        //     and System.Web.Security.SqlMembershipProvider.RequiresUniqueEmail is set
        //     to true.- or -The user update failed.
        //
        //   System.ArgumentNullException:
        //     user is null. - or -The System.Web.Security.MembershipUser.UserName property
        //     of user is null.- or -The System.Web.Security.MembershipUser.Email property
        //     of user is null and System.Web.Security.SqlMembershipProvider.RequiresUniqueEmail
        //     is set to true.
        public override void UpdateUser(MembershipUser updatedUser)
        {
            if (updatedUser == null)
                throw new System.ArgumentNullException("updatedUser");

            if (updatedUser.UserName == "" || !ValidateUserName(updatedUser.UserName))
                throw new System.ArgumentException("Username are not valid.");

            if (updatedUser.Email.Length > 256 || (updatedUser.Email.Length <= 0 && this._requiresUniqueEmail))
                throw new System.ArgumentException("Email are not valid.");

            try
            {
                if (this._requiresUniqueEmail)
                {
                    string userWithEmail = this._coreRepository.GetUserNameByEmail(updatedUser.Email);
                    if (!(userWithEmail == null || userWithEmail == updatedUser.UserName))
                        throw new System.Configuration.Provider.ProviderException(String.Format("The email '{0}' already exists in the database, this application requires unique emails.", updatedUser.Email));
                }

                User user = this._coreRepository.GetUserByUsername(updatedUser.UserName);
                
                if (user != null)
                {
                    user.Comment = updatedUser.Comment;
                    user.Email = updatedUser.Email;
                    user.IsApproved = updatedUser.IsApproved;

                    this._coreRepository.UpdateObject(user);

                }
                else
                {
                    this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("Updating user failed, username not found: {0}.", updatedUser.UserName));
                    throw new System.Configuration.Provider.ProviderException(String.Format("The updating of user '{0}' failed, username not found in database.", updatedUser.UserName));
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while trying to update user {0}.", updatedUser.UserName), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("An error occured while trying to update user {0}.", updatedUser.UserName));
            }
        }

        //
        // Summary:
        //     Verifies that the specified user name and password exist in the NHibernate
        //     membership database.
        //
        // Parameters:
        //   username:
        //     The name of the user to validate.
        //
        //   password:
        //     The password for the specified user.
        //
        // Returns:
        //     true if the specified username and password are valid; otherwise, false.
        //     A value of false is also returned if the user does not exist in the database.
        public override bool ValidateUser(string username, string password)
        {          
            try
            {
                User user = this._coreRepository.GetUserByUsername(username);

                if (user != null)
                {
                    if (!user.IsApproved || user.IsLockedOut)
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Inactive or locked user '{0}' tried to login.", user.UserName));
                        return false; 
                        //throw new System.Configuration.Provider.ProviderException("The account is disabled.");
                    }

                    if (user.ValidatePassword(password))
                    {
                        // Save login and activity date
                        user.LastActivityDate = DateTime.Now;
                        user.LastLoginDate = DateTime.Now;
                        this._coreRepository.UpdateObject(user);
                        return true;
                    }
                    else
                    {
                        this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Invalid username-password combination: {0}:{1}.", username, password));
                        return false;
                    }
                }
                else
                {
                    this._logger.Write(LogLevel.WARN, this.ToString(), String.Format("Validating... invalid username, not found in database {0}.", username));
                    return false;
                }
            }
            catch (Exception ex)
            {
                this._logger.Write(LogLevel.ERROR, this.ToString(), String.Format("An error occured while logging in user {0}.", username), ex);
                throw new System.Configuration.Provider.ProviderException(String.Format("Unable to log in user '{0}'", username), ex);
            }
        }

        #endregion

    }
}
